package com.gofgame.jumpdown.server.web;

import java.io.IOException;
import java.io.PrintWriter;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.gofgame.common.Page;
import com.gofgame.jumpdown.server.businesslogic.JumpDownService;
import com.gofgame.jumpdown.server.entities.Score;

@Controller("jump-down-controller")
@RequestMapping("/JumpDownController")
public class JumpDownController {
	
	private static final String NEW_LINE = "\n";
	
	@Resource(name = "jump-down-service")
	private JumpDownService jumpDownService;

	@RequestMapping("/submitScore")
	public void submitScore(
			@RequestParam("userName") String userName, 
			@RequestParam("level") int level,
			HttpServletResponse response) throws IOException {
		Score score = new Score();
		score.setUserName(userName);
		score.setLevel(level);
		long rank = this.jumpDownService.sumitScore(score);
		response.setContentType("text/plain");
		try (PrintWriter writer = response.getWriter()) {
			writer.println(Long.toString(rank));
		}
	}
	
	@RequestMapping("/queryScores")
	public void queryScores(
			@RequestParam("pageIndex") int pageIndex, 
			@RequestParam("pageSize") int pageSize,
			@RequestParam(value = "format", required = false) String format,
			HttpServletResponse response) throws ServletException, IOException {
		
		Page<Score> page = this.jumpDownService.queryScores(pageIndex, pageSize);
		
		Document doc;
		try {
			doc = 
					DocumentBuilderFactory
					.newInstance()
					.newDocumentBuilder()
					.newDocument();
		} catch (ParserConfigurationException ex) {
			throw new ServletException("Failed to create xml");
		}
		
		if ("json".equals(format)) {
			StringBuilder builder = new StringBuilder();
			builder.append('{').append(NEW_LINE);
			builder
			.append("\ttotoalRowCount : ")
			.append(page.getTotalRowCount())
			.append(',')
			.append(NEW_LINE);
			builder
			.append("\tpageCount : ")
			.append(page.getPageCount())
			.append(',')
			.append(NEW_LINE);
			builder
			.append("\texpectedPageIndex : ")
			.append(page.getExpectedPageIndex())
			.append(',')
			.append(NEW_LINE);
			builder
			.append("\tactualPageIndex : ")
			.append(page.getActualPageIndex())
			.append(',')
			.append(NEW_LINE);
			builder
			.append("\tpageSize : ")
			.append(page.getPageSize())
			.append(',')
			.append(NEW_LINE);
			builder
			.append("\tscores : ")
			.append('[')
			.append(NEW_LINE);
			boolean addComma = false;
			for (Score score : page) {
				if (addComma) {
					builder.append(",");
					builder.append(NEW_LINE);
				} else {
					addComma = true;
				}
				builder
				.append("\t\t{ userName : \"")
				.append(score.getUserName())
				.append("\", level : ")
				.append(score.getLevel())
				.append(" }");
			}
			builder.append(NEW_LINE).append("\t]").append(NEW_LINE);
			builder.append("}").append(NEW_LINE);
			response.setContentType("text/json");
			try (PrintWriter writer = response.getWriter()) {
				writer.write(builder.toString());
			}
		} else {
			Element scoresElement = doc.createElement("scores");
			scoresElement.setAttribute("totalRowCount", Long.toString(page.getTotalRowCount()));
			scoresElement.setAttribute("pageCount", Integer.toString(page.getPageCount()));
			scoresElement.setAttribute("expectedPageIndex", Integer.toString(page.getExpectedPageIndex()));
			scoresElement.setAttribute("actualPageIndex", Integer.toString(page.getActualPageIndex()));
			scoresElement.setAttribute("pageSize", Integer.toString(page.getPageSize()));
			for (Score score : page) {
				Element scoreElement = doc.createElement("score");
				scoreElement.setAttribute("userName", score.getUserName());
				scoreElement.setAttribute("level", Integer.toString(score.getLevel()));
				scoresElement.appendChild(scoreElement);
			}
			doc.appendChild(scoresElement);
		
			response.setContentType("text/xml");
			try (PrintWriter writer = response.getWriter()) {
				try {
					TransformerFactory
					.newInstance()
					.newTransformer()
					.transform(
							new DOMSource(doc), 
							new StreamResult(response.getWriter()));
					
					TransformerFactory
					.newInstance()
					.newTransformer()
					.transform(
							new DOMSource(doc), 
							new StreamResult(System.out));
				} catch (TransformerException | TransformerFactoryConfigurationError ex) {
					throw new ServletException("Failed to translate xml");
				}
			}
		}
	}
	
}
